package com.hsogoo.ultraman.repository;

import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;

import com.google.gson.Gson;
import com.hsogoo.ultraman.Constant;
import com.hsogoo.ultraman.container.ConfigContainer;
import com.hsogoo.ultraman.model.NamespaceConfig;
import com.hsogoo.ultraman.monitor.ConfigChangeMonitor;
import com.hsogoo.ultraman.spi.ConfigServerLocator;
import com.hsogoo.ultraman.util.AppendUtil;
import com.hsogoo.ultraman.utils.ConfigMetaUtil;
import com.hsogoo.ultraman.utils.HttpUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by za-huangsaigang on 2018/9/13.
 */
@Slf4j
public class RemoteConfigRepository extends AbstractConfigRepository {

    private final String namespace;
    private ConfigMetaUtil configMetaUtil;
    private HttpUtil httpUtil;
    private ConfigServerLocator serverLocator;
    private volatile AtomicReference<NamespaceConfig> configCache;
    private ConfigChangeMonitor configChangeMonitor;

    public RemoteConfigRepository(String namespace) {
        configCache = new AtomicReference<NamespaceConfig>();
        this.namespace = namespace;
        configMetaUtil = ConfigContainer.getBean(ConfigMetaUtil.class);
        httpUtil = ConfigContainer.getBean(HttpUtil.class);
        serverLocator = ConfigContainer.getBean(ConfigServerLocator.class);
        configChangeMonitor = ConfigContainer.getBean(ConfigChangeMonitor.class);
        //从远程配置服务器拉取配置
        updateNamespaceRemoteConfig();
        //监听远程服务器的配置变化
        configChangeMonitor.monitorRemoteConfigChange(namespace, this);
    }

    @Override
    public Properties getConfig() {
        if (configCache.get() == null) {
            this.updateNamespaceRemoteConfig();
        }
        return transformNamespaceConfigToProperties(configCache.get());
    }

    @Override
    public void setUpstreamRepository(ConfigRepository upstreamConfigRepository) {
        //remote config doesn't need upstream
    }

    public NamespaceConfig updateNamespaceRemoteConfig() {
        NamespaceConfig previous = configCache.get();
        String url = assembleQueryUrl();
        log.info(String.format("从远程配置服务器获取%s的配置。。。", namespace));
        String response = httpUtil.doGet(url);
        NamespaceConfig config = new Gson().fromJson(response, NamespaceConfig.class);
        if (previous != config) {
            configCache.set(config);
            this.fireRepositoryChange(namespace, this.getConfig());
        }

        return config;
    }

    private String assembleQueryUrl(){
        String configServerHost = serverLocator.select();
        String envName = configMetaUtil.getEnvName();
        String appName = configMetaUtil.getAppName();
        return AppendUtil.appendString(Constant.PROTOCOL_PREFIX, configServerHost, Constant.CONTEXT_PATH,
                Constant.PATH_PREFIX, envName, Constant.PATH_PREFIX, appName, Constant.PATH_PREFIX, namespace);
    }

    private Properties transformNamespaceConfigToProperties(NamespaceConfig config) {
        Properties result = new Properties();
        result.putAll(config.getConfigurations());
        return result;
    }
}
